/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ru.niir.goodfil.ui;

import com.sun.rave.web.ui.appbase.AbstractSessionBean;
import org.apache.log4j.Logger;
import ru.niir.goodfil.db.*;
import ru.niir.goodfil.db.dic.DeliveryType;
import ru.niir.goodfil.db.dic.OrderState;
import ru.niir.goodfil.db.dic.OrderType;
import ru.niir.goodfil.db.handlers.Goodfil;
import ru.niir.goodfil.exceptions.CreateFailureException;
import ru.niir.goodfil.exceptions.RemoveFailureException;
import ru.niir.goodfil.exceptions.SettingNotFoundException;
import ru.niir.goodfil.exceptions.ValidationException;
import ru.niir.goodfil.ui.audit.JsfAuditHelper;
import ru.niir.goodfil.ui.utils.PathGoodsType;
import ru.niir.goodfil.utils.Pair;
import ru.niir.goodfil.utils.PricelistItem;
import ru.niir.goodfil.utils.filters.*;

import javax.faces.application.FacesMessage;
import javax.faces.model.SelectItem;
//import javax.xml.rpc.holders.LongWrapperHolder;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static ru.niir.goodfil.utils.Utils._assertNotNull;

/**
 * Сессиоанный бин приложения. Хранит данные, которые должны быть переданы между различными страницами/бинами.
 *
 * @author nosov
 * @author Сазонов К.Н. sazonovkirill@gmail.com
 * @version 0.8
 */

public class SessionBean extends AbstractSessionBean {
    private static final String SECURITY_BEAN_KEY = "SecurityBean";

    private static Logger logger = Logger.getLogger(SessionBean.class);


    /**
     * Идентификатор выбранного клиента. Нужен для перехода между страницами ClientsPage.jsp и Client.jsp. Пользователь
     * выбирает клиента для редактирования на странице ClientsPage.jsp и его идентификатор записывается в данное поле.
     * После этого происходит переход на страницу Client.jsp и она считывает это значения для отображения параметров
     * редактируемого клиента.
     * <p/>
     * ВНИМАНИЕ: Это же поле используется и для хранения идентификатора зарегистрированного клиента через
     * ClientHeader.jsp. Сбрасывается при выходе клиента.
     */
    private long selectedClientId = -1;

    /**
     * Идентификатор выбранного заказа. Нужен для фиксации активного заказа в который клиент добавляет товар. Нужен для
     * перехоода между страницами OrdersPage.jsp и OrderPage.jsp.
     */
    private long selectedOrderId = -1;

    /**
     * Путь для каталога товаров клиентов.
     */
    private List<PathGoodsType> path;

    /**
     * Список товаров в корзине
     */
    private List<OrderItem> orderItems = new ArrayList<OrderItem>();

    /**
     * Корзина
     */
    private Order order = new Order();

    /**
     * Идентификатор прайса
     */
    private long idPriselist = -1;

    /**
     * Доступ к бд
     */
    private Goodfil goodfil;

    /**
     * Видимо что то очень нужное
     */
    private Map<String, Object> storedObjects = new HashMap<String, Object>();

    /**
     * Список выбранных товаров
     */
    private final Set<Long> selectedGoods = new HashSet<Long>();

    /**
     * Идентификатор
     */
    private long longId;

    /**
     * Страица товаров
     */
    private int goodsPage = 1;

    /**
     * Страница прайса
     */
    private int pricelistPage = 1;

    /**
     * Страница пользователя
     */
    private int usersPage = 1;

    /**
     * Страница замещения
     */
    private int replacementsPage = 1;

    /**
     * Страница персональных цен
     */
    private int personalPricesPage = 1;

    /**
     * Страница клиентов
     */
    private int clientsPage = 1;

    /**
     * Страница в таблице товаров для клиента
     */
    private int clientGoodsSearchPage = 1;

    /**
     * Фильтр товара
     */
    private GoodsFilter goodsFilter = new GoodsFilter();

    /**
     * Фильтр прайса
     */
    private GoodsFilter _pricelistFilter = new GoodsFilter();

    /**
     * Фильтр пользователя
     */
    private UsersFilter usersFilter = new UsersFilter();

    /**
     * Фильтр замещений
     */
    private ReplacementsFilter replacementsFilter = new ReplacementsFilter();

    /**
     * Фильтр персональных цен
     */
    private PersonalPricesFilter personalPricesBean = new PersonalPricesFilter();

    /**
     * Фильтр клиентов
     */
    private ClientsFilter clientsFilter = new ClientsFilter();

    /**
     * Фильтр заказа
     */
    private OrdersFilter ordersFilter = new OrdersFilter();

    private PricelistFilter pricelistFilter = new PricelistFilter();

    /**
     * Список прейскурантов
     */
    private List<PricelistItem> pricelistItems;

    public SessionBean() {
        goodfil = GoodfilFactory.getInstance();
        goodfil.setAuditHelper(new JsfAuditHelper());
    }

    /**
     * Возвращает идентификатор выбранного клиента.
     *
     * @return идентификатор клиента
     */
    public long getSelectedClientId() {

        return selectedClientId;
    }

//    /**
//     * Возвращает идентификатор клиентской группы для текущего (выбранного) клиента.
//     * При определении клиентской группы используется расширенный алгоритм.
//     */
//    public long getSelectedClientGroupId()
//    {
//        return goodfil.getClientGroupByClientId(selectedClientId);
//    }

    public long getSelectedClientGroupId2(long brandId) {
        return goodfil.getClientGroupByClientId2(selectedClientId, brandId);
    }

    /**
     * Устанавливает идентификатор выбранного клиента.
     *
     * @param selectedClientId идентификатор клиента
     */
    public void setSelectedClientId(long selectedClientId) {
        this.selectedClientId = selectedClientId;
    }

    /**
     * Возвращает идентификатор выбранного заказа.
     *
     * @return идетификатор
     */
    public long getSelectedOrderId() {
        return selectedOrderId;
    }

    /**
     * Устанавдивает идентификатор выранного заказа.
     *
     * @param selectedOrderId идентификатор
     */
    public void setSelectedOrderId(long selectedOrderId) {
        this.selectedOrderId = selectedOrderId;
    }

    /**
     * Возвращает путь группы товаров в котором находится клиент.
     *
     * @return путь
     */
    public List<PathGoodsType> getPath() {
        /*
            Почему-то это место с двух раз на третий вылетает с исключением, поэтому пришлось сделать тупо но верно
         */
        for (int i = 0; i < 10; i++) {
            try {
                return _getPath();
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * Возвращает путь группы товаров в котором находится клиент.
     *
     * @return путь
     */
    public List<PathGoodsType> _getPath() {
        path = new ArrayList<PathGoodsType>();
        long parent = goodsFilter.getGoodTypeId();
        while (parent > 1) {
            GoodType goodType = goodfil.getGoodTypeById(parent);
            path.add(new PathGoodsType(goodType.getId(), goodType.getName(), goodType.getParentId()));
            parent = goodType.getParentId();
        }
        Collections.sort(path, new Comparator<PathGoodsType>() {
            public int compare(PathGoodsType i1, PathGoodsType i2) {
                return (int) (i1.getParentId() - i2.getParentId());
            }
        });
        return path;
    }

    /**
     * Возвращает список товаров в активном заказе.
     *
     * @return список товаров в заказе
     */
    public List<OrderItem> getOrderItems() {
        if (selectedClientId > 0) {
            orderItems = goodfil.getOrderItemsByOrderId(selectedOrderId);
            for (OrderItem orderItem : orderItems) {
                orderItem.setGood(goodfil.getGoodById(orderItem.getGoodId()));
            }
        }
        return orderItems;
    }

    public Map<Long, Long> getOrderItemsMap() {
        Map<Long, Long> result = new HashMap<Long, Long>();
        for (OrderItem orderItem : getOrderItems()) {
            result.put(orderItem.getGood().getId(), (long) orderItem.getCount());
        }

        return result;
    }

    /**
     * Возвращает заказ клиента.
     */
    public Order getOrder() {
        return order;
    }

    /**
     * Устанавливает заказ клиента.
     *
     * @param order заказ
     */
    public void setOrder(Order order) {
        this.order = order;
    }

    /**
     * Возвращает идентификатор выбранного прейскуранта.
     *
     * @return идентификатор прейскуранта
     */
    public long getIdPriselist() {
        return idPriselist;
    }

    /**
     * Устанавливает идентификатор выбранного прейскуранта.
     *
     * @param idPriselist идентификатор прейскуранта
     */
    public void setIdPriselist(long idPriselist) {
        this.idPriselist = idPriselist;
    }

    /**
     * Возвращает соединение с БД.
     *
     * @return соединение
     */
    public Goodfil getGoodfil() {
        return goodfil;
    }

    /**
     * Возвращает карту чего то нужного.
     *
     * @return карта чего то нужного
     */
    public Map<String, Object> getStoredObjects() {
        return storedObjects;
    }

    /**
     * Добавляет в карту объект чего нибуть нужного.
     *
     * @param key ключ
     * @param o   объект
     */
    protected void putObject(String key, Object o) {
        storedObjects.put(key, o);
    }

    /**
     * Возвращает из карты объект чего то нужного.
     *
     * @param key ключ
     * @return объект
     */
    protected Object takeObject(String key) {
        if (!storedObjects.containsKey(key)) {
            return null;
        }

        Object o = storedObjects.get(key);
        storedObjects.remove(key);
        return o;
    }

    /**
     * Возвращает список выбранных товаров.
     *
     * @return список товаров
     */
    public Set<Long> getSelectedGoods() {
        return selectedGoods;
    }

    /**
     * Добавляет выбранный товар.
     */
    public void addSelectedGood() {
        if (selectedGoods.contains(getLongId())) {
            selectedGoods.remove(getLongId());
        } else {
            selectedGoods.add(getLongId());
        }
    }

    /**
     * Возвращает идентификатор чего то.
     *
     * @return идентификатор чего то
     */
    public long getLongId() {
        return longId;
    }

    /**
     * Устанавливает идентификатор чего то.
     *
     * @param longId идентифифкатор чего то
     */
    public void setLongId(long longId) {
        this.longId = longId;
    }

    /**
     * Возвращает страницу товаров.
     *
     * @return страница товаров
     */
    public int getGoodsPage() {
        return goodsPage;
    }

    /**
     * Устанавливает страницу товаров
     *
     * @param goodsPage страница товаров
     */
    public void setGoodsPage(int goodsPage) {
        this.goodsPage = goodsPage;
    }

    /**
     * Возвращает страницу прайса.
     *
     * @return страница прайса
     */
    public int getPricelistPage() {
        return pricelistPage;
    }

    /**
     * Устанавливает страницу прайса.
     *
     * @param pricelistPage страница прайса
     */
    public void setPricelistPage(int pricelistPage) {
        this.pricelistPage = pricelistPage;
    }

    /**
     * Возвращает страницу пользователя.
     *
     * @return страница пользователя
     */
    public int getUsersPage() {
        return usersPage;
    }

    /**
     * Устанавливает страницу пользователя.
     *
     * @param usersPage страница пользователя.
     */
    public void setUsersPage(int usersPage) {
        this.usersPage = usersPage;
    }

    /**
     * Возвращает страницу замещений.
     *
     * @return страница замещений
     */
    public int getReplacementsPage() {
        return replacementsPage;
    }

    /**
     * Устанавливает страницу замещений.
     *
     * @param replacementsPage страница замещений
     */
    public void setReplacementsPage(int replacementsPage) {
        this.replacementsPage = replacementsPage;
    }

    /**
     * Возвращает страницу персональных цен.
     *
     * @return страница персональных цен
     */
    public int getPersonalPricesPage() {
        return personalPricesPage;
    }

    public int getClientGoodsSearchPage() {
        return clientGoodsSearchPage;
    }

    public void setClientGoodsSearchPage(int clientGoodsSearchPage) {
        this.clientGoodsSearchPage = clientGoodsSearchPage;
    }

    /**
     * Устанавливает страницу персональных цен.
     *
     * @param personalPricesPage страница персональных цен
     */
    public void setPersonalPricesPage(int personalPricesPage) {
        this.personalPricesPage = personalPricesPage;
    }

    /**
     * Возвращает страницу клиентов.
     *
     * @return страница клиентов
     */
    public int getClientsPage() {
        return clientsPage;
    }

    /**
     * Устанавливает страницу клиентов.
     *
     * @param clientsPage страница клиентов
     */
    public void setClientsPage(int clientsPage) {
        this.clientsPage = clientsPage;
    }

    /**
     * Возвращает фильтр товаров.
     *
     * @return фильтр товаров
     */
    public GoodsFilter getGoodsFilter() {
        return goodsFilter;
    }

    /**
     * Устанвливает фильтр товаров.
     *
     * @param goodsFilter фильтр товаров
     */
    public void setGoodsFilter(GoodsFilter goodsFilter) {
        this.goodsFilter = goodsFilter;
    }

    /**
     * Возвращает фильтр пользователя.
     *
     * @return фильтр пользователя
     */
    public UsersFilter getUsersFilter() {
        return usersFilter;
    }

    /**
     * Устанавливает фильтр пользователя.
     *
     * @param usersFilter фильтр пользователя
     */
    public void setUsersFilter(UsersFilter usersFilter) {
        this.usersFilter = usersFilter;
    }

    /**
     * Возвращает фильтр замещений.
     *
     * @return фильтр замещений
     */
    public ReplacementsFilter getReplacementsFilter() {
        return replacementsFilter;
    }

    /**
     * Устанавливает фильтр замещений.
     *
     * @param replacementsFilter фильтр замещений
     */
    public void setReplacementsFilter(ReplacementsFilter replacementsFilter) {
        this.replacementsFilter = replacementsFilter;
    }

    /**
     * Возвращает фильтр персональных цен.
     *
     * @return фильтр персональных цен
     */
    public PersonalPricesFilter getPersonalPricesFilter() {
        return personalPricesBean;
    }

    /**
     * Устанавливает фильтр персональных цен.
     *
     * @param personalPricesBean фильтр персональных цен
     */
    public void setPersonalPricesFilter(PersonalPricesFilter personalPricesBean) {
        this.personalPricesBean = personalPricesBean;
    }

    /**
     * Возвращает фильтр прайса.
     *
     * @return фильтр прайса.
     */
    public GoodsFilter get_pricelistFilter() {
        return _pricelistFilter;
    }

    /**
     * Устанавливает фильтр прайса.
     *
     * @param _pricelistFilter фильтр прайса
     */
    public void set_pricelistFilter(GoodsFilter _pricelistFilter) {
        this._pricelistFilter = _pricelistFilter;
    }

    public PricelistFilter getPricelistFilter() {
        return pricelistFilter;
    }

    public void setPricelistFilter(PricelistFilter pricelistFilter) {
        this.pricelistFilter = pricelistFilter;
    }

    /**
     * Возвращает фильтр клиентов.
     *
     * @return фильтр клиентов
     */
    public ClientsFilter getClientsFilter() {
        return clientsFilter;
    }

    /**
     * Устанавливает фильтр клиентов.
     *
     * @param clientsFilter фильтр клиентов
     */
    public void setClientsFilter(ClientsFilter clientsFilter) {
        this.clientsFilter = clientsFilter;
    }

    /**
     * Возвращает фильтр заказов.
     *
     * @return заказов
     */
    public OrdersFilter getOrdersFilter() {
        return ordersFilter;
    }

    /**
     * Устанавливает фильтр заказов.
     *
     * @param ordersFilter фильтр заказов
     */
    public void setOrdersFilter(OrdersFilter ordersFilter) {
        this.ordersFilter = ordersFilter;
    }

    /**
     * Возвращает список прейскурантов.
     *
     * @return список прейскурантов
     */
    public List<PricelistItem> getPricelistItems() {
        return pricelistItems;
    }

    /**
     * Устанавливает список прейскурантов.
     *
     * @param pricelistItems список прейскурантов
     */
    public void setPricelistItems(List<PricelistItem> pricelistItems) {
        this.pricelistItems = pricelistItems;
    }


    public String getHelloWorld() {
        return "Hello, world!";
    }

    public void setHelloWorld(String s) {
    }

    /**
     * Возвращает название компании.
     *
     * @return название компании
     */
    public String getCompanyName() {
        if (selectedClientId > 0) {
            return goodfil.getClientById(selectedClientId).getCompanyName();
        } else {
            return "";
        }
    }

    /**
     * Возвращает список заказов для клиента.
     *
     * @return список
     */
    public List<Order> getOrdersListForClient() {
        List<Order> orders = null;
        if (selectedClientId > 0) {
            orders = goodfil.getOrdersByClientId(selectedClientId);
        }
        return orders;
    }

    /**
     * @param orderState
     * @return
     */
    private boolean getOrderStateIs(int orderState) {
        return order.getOrderStateId() == orderState;
    }

    /**
     * @return
     */
    public boolean getOrderStateIsPreSaved() {
        return getOrderStateIs(OrderState.PRE_SAVED);
    }

    /**
     * @return
     */
    public boolean getOrderStateIsSaved() {
        return getOrderStateIs(OrderState.SAVED);
    }

    /**
     * @return
     */
    public boolean getOrderStateIsAwaitingValidation() {
        return getOrderStateIs(OrderState.AWAITING_VALIDATION);
    }

    /**
     * @return
     */
    public boolean getOrderStateIsValidated() {
        return getOrderStateIs(OrderState.VALIDATED);
    }

    /**
     * @return
     */
    public boolean getOrderStateIsNotValidated() {
        return getOrderStateIs(OrderState.NOT_VALIDATED);
    }

    /**
     * Созвращает true, если состав заказа можно изменять. А состав заказа можно изменять только пока заказ находится в
     * статуах:
     * <p/>
     * OrderState.PRE_SAVED, OrderState.SAVED, OrderState.AWAITING_VALIDATION, OrderState.NOT_VALIDATED
     */
    public boolean getOrderStateIsBeforeSaved() {

        return getOrderStateIsPreSaved() ||
                getOrderStateIsSaved() ||
//                getOrderStateIsAwaitingValidation() ||
                getOrderStateIsNotValidated();
    }

    /**
     * Возвращает true, если текущий заказ содержит позиции (т.е. не пуст)
     *
     * @return true, если текущий заказ содержит позиции (т.е. не пуст)
     */
    public boolean getOrderIsNotEmpty() {
        return !(getOrderItems() == null || getOrderItems().size() == 0);
    }

    /**
     * Возвращает true, если у клиента, относящегося к текущему заказу нет долга.
     */
    public boolean getClientCanSaveOrder() {
        return goodfil.clientCanSaveOrder(selectedClientId);
    }

    public String getClientManagerFio() {
        Client client = goodfil.getClientById(selectedClientId);
        if (client != null) {
            User manager = goodfil.getUserById(client.getManagerId());
            if (manager != null) {
                return manager.getFio();
            }
        }

        return null;
    }

    public String getClientManagerEmail() {
        Client client = goodfil.getClientById(selectedClientId);
        if (client != null) {
            User manager = goodfil.getUserById(client.getManagerId());
            if (manager != null) {
                return manager.getEmail();
            }
        }

        return null;
    }

    /**
     * вот такие методы я называю - охуеть. Добаляет/удаляет товар в заказе. Или изменяет количество товара в заказе.
     * Если пользователь не авторизован, то заказ сохранен только в сесии. Если пользователь авторизован, то
     * активируется последний заказ со статусом "предварительно сохранен" и если пользователь в неавторизованном виде
     * набрал еще товара, то заказы сливаются.
     *
     * @param orderItems список товаров в заказе
     */
    public synchronized void setOrderItems(List<OrderItem> orderItems) throws RemoveFailureException, CreateFailureException, ValidationException, SettingNotFoundException {
        if (selectedClientId > 0) {   // Если пользователь авторизован

            //  Надеемся, что клиент уже в кэше
            Client client = goodfil.getClientById(selectedClientId);
            _assertNotNull(client);

            if (selectedOrderId == -1) {   // Проверяем загружен ли заказ

                Order lastPresavedOrder = goodfil.getLastPresavedOrder(selectedClientId);
                if (lastPresavedOrder == null) {   // У пользователя нет заказа со статусом "предварительно сохранен" => создаем новый заказ

                    logger.debug("Creating new order");
                    Order newOrder = OrderBuilder.createOrder(goodfil, client);
                    goodfil.saveOrder(newOrder);

                    order = newOrder;
                    selectedOrderId = newOrder.getId();

                    // Сохранение товаров в заказ
                    for (OrderItem orderItem : orderItems) {
                        orderItem.setOrderId(order.getId());
                        if (orderItem.getId() == -1) {
                            goodfil.saveOrderItem(orderItem);
                        }
                    }
                } else {   // У пользователя есть заказ. Слияние заказа и набранных товаров до регистрации.

                    order = lastPresavedOrder;
                    selectedOrderId = lastPresavedOrder.getId();

                    logger.debug("Orders' concatenation");
                    List<OrderItem> ordersInDBList = goodfil.getOrderItemsByOrderId(selectedOrderId);
                    for (OrderItem orderInDB : ordersInDBList) {
                        for (int i = 0; i < orderItems.size(); i++) {
                            OrderItem orderItem = orderItems.get(i);
                            if (orderInDB.getGoodId() == orderItem.getGoodId()) {   // Если товар в корзине то же что и в бд тогда складываем их количество и удаляем заказ из корзины

                                orderInDB.setCount(orderInDB.getCount() + orderItem.getCount());
                                goodfil.cleverUpdateOrderItem(orderInDB);
                                orderItems.remove(i);
                            }
                        }
                    }
                    // Если в корзине остались товары их надо добавить в заказ. Это сделает метод ниже.
                }
            }

            // Обновляем данные в БД
            for (OrderItem orderItem : orderItems) {   // Товар в сесии
                if (orderItem.getId() == -1) {   // Проверяем наличие товара в заказе.
                    // Т.к. пользователь авторизован, то его заказ синхронизирован с БД и, следовательно,
                    // товар который мы добаляем не может иметь идентификатор -1.
                    orderItem.setOrderId(order.getId());
                    goodfil.saveOrderItem(orderItem);           // Добавление нового товара в заказ.
                } else {
                    goodfil.cleverUpdateOrderItem(orderItem);   // Изменение количества товара в заказе.
                }

                if (orderItem.getCount() <= 0) {
                    orderItems.remove(orderItem);
                }
            }

            orderItems = goodfil.getOrderItemsByOrderId(selectedOrderId);       // Вытаскиваем измененый заказ клиента.
            goodfil.addOrderInfo(order);                                        // Расчет стоимости заказа и доставки
        }

        // Если пользователь не авторизован, но при этом работает с заказом и чего то удаляет из заказа, то это надо отразить в сесии.
        for (int i = 0; i < orderItems.size(); ) {
            OrderItem orderItem = orderItems.get(i);
            if (orderItem.getCount() <= 0) {
                orderItems.remove(i);
            } else {
                i++;
            }
        }

        this.orderItems = orderItems;
    }

    /**
     * Возвращает количество позиций в активной корзине.
     *
     * @return количество позиций
     */
    public long getOrderItemsCount() {
        assert getOrderItems() != null;

        logger.trace("getOrderItemCount(): " + getOrderItems().size());
        return getOrderItems().size();
    }

    /**
     * Возвращает количество товара в активной корзине.
     *
     * @return количество товара
     */
    public long getOrderGoodsCount() {
        assert getOrderItems() != null;

        long result = 0;
        for (OrderItem orderItem : getOrderItems()) {
            result += orderItem.getCount();
        }
        return result;
    }

    /**
     * Возвращает сумму товаров в активной корзине.
     *
     * @return сумма товаров
     */
    public float getOrderPrice() {
        _assertNotNull(getOrderItems());

        float result = 0;
        for (OrderItem orderItem : getOrderItems()) {
            result += orderItem.getSum();
        }
        return new BigDecimal(String.valueOf(result)).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * Возвращает стоимость доставки.
     *
     * @return стоимость доставки
     */
    public float getDeliverySum() {
        _assertNotNull(order);

        int deliveryCompanyMoney = goodfil.getInt("delivery.company.money");
        int deliveryFreeMoney = goodfil.getInt("delivery.free.money");
        int deliveryEdge = goodfil.getInt("delivery.edge");

        float sum = getOrderPrice();
        float deliverySum = order.getDeliveryTypeId() == DeliveryType.COMPANY ? (sum >= deliveryEdge ? deliveryFreeMoney : deliveryCompanyMoney) : 0;
        return new BigDecimal(String.valueOf(deliverySum)).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    public float getTotal() {
        float result = getDeliverySum() + getOrderPrice();
        return new BigDecimal(String.valueOf(result)).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue();
    }

    /**
     * Возвращает true, если в сессионном бине установлен идентификатор "текущего" клиента
     *
     * @return true, если в сессионном бине установлен идентификатор "текущего" клиента
     */
    public boolean getClientIsSelected() {
        return selectedClientId != -1;
    }

    public long getOrdersCount() {
        OrdersFilter filter = new OrdersFilter();
        filter.setClientId(selectedClientId);
        return goodfil.getOrdersCount(filter);
    }

    public List<SelectItem> getOrderTypes() {
        List<Pair> types = OrderType.list();
        List<SelectItem> result = new ArrayList<SelectItem>();
        for (Pair type : types) {
            result.add(new SelectItem(type.getId(), type.getValue()));
        }
        return result;
    }

    private List<CircularTable> pickListSelectedUser = new ArrayList<CircularTable>();

    public void addPickListSelectedUser(Object obj) {
        if (obj instanceof User) {
            User user = (User) obj;
            pickListSelectedUser.add(new CircularTable(user, user.getFio()));
        } else if (obj instanceof Client) {
            Client client = (Client) obj;
            pickListSelectedUser.add(new CircularTable(client, client.getCompanyName()));
        }
    }

    public void removePickListSelectedUser(CircularTable ct) {
        pickListSelectedUser.remove(ct);
    }

    public List<CircularTable> getPickListSelectedUser() {
        return pickListSelectedUser;
    }

    public void setPickListSelectedUser(List<CircularTable> PickListSelectedUser) {
        this.pickListSelectedUser = PickListSelectedUser;
    }


    protected SecurityBean getSecurityBean() {
        return (SecurityBean) getBean(SECURITY_BEAN_KEY);
    }

    public void resetNewOrderFilters() {
        goodsFilter = new GoodsFilter();
    }

    //
    //  Редактирование клиента
    //
    private Client editableClient = new Client();

    public long getEditableClientId() {
        if (editableClient == null) {
            return -1;
        } else {
            return editableClient.getId();
        }
    }

    public void setEditableClientId(long editableClientId) {
        logger.info("EDIT CLIENT: " + editableClientId);
        if (editableClient != null && editableClient.getId() == editableClientId) {
            return;
        } else {
            editableClient = getGoodfil().getClientById(editableClientId);
            if (editableClient == null) {
                logger.info("Creating new client in SessionBean");
                editableClient = new Client();
                editableClient.initVisibleBrands();
                editableClient.initVisibleClientGroups();

                for (Brand brand : getGoodfil().getBrands()) {
                    editableClient.getClientgroups().put(brand.getId(), 0L);
                }
            }
        }
    }

    public Client getEditableClient() {
        return editableClient;
    }

    public void setEditableClient(Client editableClient) {
        this.editableClient = editableClient;
    }

    //
    //  Редактирование товара
    //
    private Good editableGood = new Good();

    public void setEditableGoodId(long editableGoodId) {
        if (editableGood != null && editableGood.getId() == editableGoodId) {
            return;
        } else {
            editableGood = goodfil.getGoodById(editableGoodId);
            if (editableGood == null) {
                editableGood = new Good();
            }
        }
    }

    public Good getEditableGood() {
        return editableGood;
    }

    public void setEditableGood(Good editableGood) {
        this.editableGood = editableGood;
    }


    private Map variables = new ConcurrentHashMap();

    protected void setVariable(String key, int iValue) {
        if (!variables.containsKey(key)) {
            logger.debug("Session INT variable `" + key + "` was created");
        }
        variables.put(key, iValue);
    }

    protected void setVariable(String key, long lValue) {
        if (!variables.containsKey(key)) {
            logger.debug("Session LONG variable `" + key + "` was created");
        }
        variables.put(key, lValue);
    }

    protected void setVariable(String key, String sValue) {
        if (!variables.containsKey(key)) {
            logger.debug("Session STRING variable `" + key + "` was created");
        }
        variables.put(key, sValue);
    }

    protected int getIntVariable(String key) {
        if (!variables.containsKey(key)) {
            logger.debug("Session INT variable `" + key + "` was created");
            variables.put(key, 0);
        }
        return (Integer) variables.get(key);
    }

    protected long getLongVariable(String key) {
        if (!variables.containsKey(key)) {
            logger.debug("Session LONG variable `" + key + "` was created");
            variables.put(key, 0L);
        }
        return (Long) variables.get(key);
    }

    protected String getStringVariable(String key) {
        if (!variables.containsKey(key)) {
            logger.debug("Session STRING variable `" + key + "` was created");
            variables.put(key, "");
        }
        return (String) variables.get(key);
    }

    /**
     * Возвращает информацию о наличии ошибок.
     *
     * @return <b>true</b>-есть</br> <b>false</b>-нет
     */
    protected boolean hasFacesErrors() {
        return getFacesContext().getMaximumSeverity() == FacesMessage.SEVERITY_ERROR;
    }

    /**
     * Возвращает
     *
     * @return
     */
    public boolean getHasFacesErrors() {
        return hasFacesErrors();
    }

    public void refreshOrder() {
        this.setOrder(goodfil.getOrderById(getSelectedOrderId()));
    }
}
